package de.cdtm.whackathon.bloodwine.client;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.cobogw.gwt.waveapi.gadget.client.Participant;
import org.cobogw.gwt.waveapi.gadget.client.WaveFeature;

import com.google.gwt.core.client.JsArray;

public class BloodwineState {
	private static final String OPTIONS_KEY = "options";
	private static final String SEPARATOR = "|";
	private final WaveFeature wave;
	
	public BloodwineState(WaveFeature wave) {
		this.wave = wave;
	}
	
	private String getViewer() {
		return wave.getViewer().getId();
	}
	
	public Set<String> getChoices(String participant) {
		Set<String> optionsSet = new HashSet<String>();
		if (wave.getState() != null) {
			String optionsString = wave.getState().get(participant);
			if (optionsString != null) {
				String[] optionsArray = optionsString.split("\\"+SEPARATOR);
				optionsSet.addAll(Arrays.asList(optionsArray));
			}
		}
		return optionsSet;
	}
	
	public Map<String, Set<String>> getChoices() {
		HashMap<String, Set<String>> allParticipantsWithOptions = new HashMap<String, Set<String>>();
		
		JsArray<Participant> participants = wave.getParticipants();
		
		for (int i = 0; i < participants.length(); i++) {
			String participant = participants.get(i).getId();
			
			if (wave.getState().get(participant) != null) {
				Set<String> optionsForParticipant = getChoices(participant);
				if (!optionsForParticipant.isEmpty()) {
					allParticipantsWithOptions.put(participant, optionsForParticipant);
				}
			}
		}
		
		return allParticipantsWithOptions;
	}
	
	public Set<String> getOwnChoices() {
		return getChoices(getViewer());
	}

	public void setChoice(String participant, String option, boolean choice) {
		Map<String, Set<String>> choices = getChoices();
		
		if(choices.get(getViewer()) == null)
			choices.put(getViewer(), new HashSet<String>());
		
		Set<String> participantChoices = choices.get(participant);
		
		if(participantChoices == null)
			participantChoices = new HashSet<String>();
		
		if(choice)
			participantChoices.add(option);
		else
			participantChoices.remove(option);

		String optionsStringOfParticipant = "";
		
		for(String thisOption : participantChoices)
			optionsStringOfParticipant += thisOption + SEPARATOR;
		
		HashMap<String, String> map = new HashMap<String, String>();
		map.put(participant, optionsStringOfParticipant);
		wave.getState().submitDelta(map);
	}
	
	public void setChoice(String option, boolean choice) {
		setChoice(getViewer(), option, choice);
	}

	private void submitOptions(Set<String> options) {
		StringBuilder optionsString = new StringBuilder();
		for(String o : options) {
			optionsString.append(o);
			optionsString.append(SEPARATOR);
		}
		optionsString.setLength(optionsString.length()-1);

		HashMap<String, String> map = new HashMap<String, String>();
		map.put(OPTIONS_KEY, optionsString.toString());
		wave.getState().submitDelta(map);
	}
	
	public void addOption(String option) {
		Set<String> options = getOptions();
		
		if(option.isEmpty())
			throw new IllegalArgumentException("Option must not be empty.");
		if(option.contains(SEPARATOR))
			throw new IllegalArgumentException("Option must not contain '"+SEPARATOR+"'.");
		if(options.contains(option))
			throw new IllegalArgumentException("Option already added.");

		options.add(option);
		submitOptions(options);
	}
	
	public void removeOption(String optionToRemove) {
		Set<String> options = new HashSet<String>(getOptions());
		options.remove(optionToRemove);
		submitOptions(options);
		
		JsArray<Participant> participants = wave.getParticipants();
		for(int i=0; i<participants.length(); i++)
			setChoice(participants.get(i).getId(), optionToRemove, false);
	}
	
	public Set<String> getOptions() {
		Set<String> optionsList = new HashSet<String>();
		if(wave.getState() != null) {
			String optionsString = wave.getState().get(OPTIONS_KEY);
			if(optionsString != null)
				optionsList.addAll(Arrays.asList(optionsString.split("\\"+SEPARATOR)));
		}
		return optionsList;
	}
	
	public Participant getParticipantById(String id) {
		return wave.getParticipantById(id);
	}
}
